// 对象深度比较
// 1.值类型，直接比较即可
// 2.引用类型，递归比较
// 3.需考虑正则、函数等类型的比较

const isArray = require('./isArray')
const isNumber = require('./isNumber')
const isRegExp = require('./isRegExp')
const isDate = require('./isDate')
const isBoolean = require('./isBoolean')
const isString = require('./isString')

function isEqual(o1, o2) {
  // 1.值类型比较 [String | Number | Boolean | null | undefined]
  if (o1 === o2) return true

  // 2.正则
  if (isRegExp(o1)) {
    return '' + o1 === '' + o2
  }

  // 3.日期和布尔
  if (isDate(o1) || isBoolean(o1)) {
    // + 号的作用
    // 布尔：o1:true -> +o1:1
    // 日期：o1:Sun Jan 23 2022 10:34:09 GMT+0800 (中国标准时间) -> +o1:1642905249716
    return +o1 === +o2
  }

  // 4.引用类型比较
  if (
    o1 &&
    o2 &&
    !isNumber(o1) &&
    !isNumber(o2) &&
    !isString(o1) &&
    !isString(o2)
  ) {
    // 4.1 数组及其他类型
    const isO1Arr = isArray(o1)
    const isO2Arr = isArray(o2)

    // 若有一个为数组，则判断两个对象是否都为数组；若都不为数组，则判断对象实例是否属于同一个父类
    // 都为同一个类型后再进行深度比较，否则直接返回 false
    if (
      isO1Arr || isO2Arr
        ? isO1Arr && isO2Arr
        : o1.constructor === o2.constructor
    ) {
      const k1 = Object.keys(o1)
      const k2 = Object.keys(o2)

      if (k1.length !== k2.length) return false

      let isE = false
      for (let key in o1) {
        // 若key非自身属性，则说明key属性原型链上，而非该示例上的，因此不相等
        if (!o2.hasOwnProperty(key)) {
          return false
        }

        isE = isEqual(o1[key], o2[key])
        if (!isE) return isE
      }
      return isE
    } else {
      // 两个实例的类型不一样，直接返回false
      return false
    }
  }
  // 其他不符合的情况，如 [只传一个参数 | 两个不相等的String类型 ...]
  return false
}

module.exports = isEqual

// console.log(isEqual({ bb: 22 }, { aa: 11, bb: 22 })) // false
// console.log(isEqual({}, [])) // false
// console.log(isEqual({ 0: 1 }, [1])) // false
// console.log(isEqual(true, false)) // false
// console.log(isEqual({ name: 'test1' }, { name: 'test1' })) // true
// console.log(
//   isEqual(
//     { name: 'test1', list: [11, /\d/] },
//     { name: 'test1', list: [11, /\d/] }
//   )
// ) // true
// console.log(
//   isEqual(
//     { name: 'test1', list: [11, 33, { a: /\D/ }] },
//     { name: 'test1', list: [11, 33, { a: /\d/ }] }
//   )
// ) // false
// console.log(isEqual(new Date('2020-01-01'), new Date('2020-01-05'))) // false
